#include <iostream>
#include <boost/python.hpp>

class A
{
public:
   // This makes A polymorphic, which is required for run-time type conversion
   // in Boost.Python.
   virtual ~A()
   {
   }
};

class B : public A
{
public:
   void f()
   {
      std::cout << "Non-virtual B::f()" << std::endl;
   }

   void g()
   {
      std::cout << "Non-virtual B::g()" << std::endl;
   }
};

// This class will not be exposed to Python.
class C : public B
{
   void g()
   {
      std::cout << "Non-virtual C::g()" << std::endl;
   }
};

// Return an instance of the derived class, but use the base class.
A* createObj()
{
   return new B;
}

// This must get an instance of the derived class.
void call(B* obj)
{
   obj->g();
}

// Return an instance of the unexposed derived class, but return it as an A.
A* createObj2()
{
   return new C;
}

// Return an instance of the unexposed derived class, but return it as a B.
B* createObj3()
{
   return new C;
}

using namespace boost::python;

BOOST_PYTHON_MODULE(testrtti)
{
   class_<A>("A", init<>())
   ;

   class_<B, bases<A> >("B", init<>())
      .def("f", &B::f)
      .def("g", &B::g)
   ;

   def("createObj", createObj, return_value_policy<manage_new_object>());
   def("call", (void(*)(B*)) call);
   def("createObj2", createObj2, return_value_policy<manage_new_object>());
   def("createObj3", createObj3, return_value_policy<manage_new_object>());
}
